﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Joins;
using System.Reactive.Threading;
using System.Runtime.CompilerServices;

using IBApi;

namespace IBRx {
    	public class SubjectFactory : IDisposable {
		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual ISubject<T> createSubject<T>() {
            return new Subject<T>();
		}

		private readonly List<dynamic> items = new List<dynamic>();

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public virtual ISubject<T> GetNew<T>() {
			ISubject<T> newSubject = createSubject<T>();
			items.Add(newSubject);
			return newSubject;
		}

		private static SubjectFactory sf;
		public static SubjectFactory Instance { 
			get {
				if (sf == null) sf = new SubjectFactory();

				return sf;
			}
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected SubjectFactory() {
			if (sf != null) throw new InvalidOperationException("Static instance of SubjectFactory already set");

			sf = this;
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		private void cleanUp() {
			lock(items) {
				items.ForEach(i => i.OnCompleted());
				items.RemoveAll(i => true);
			}
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		~SubjectFactory() {
			cleanUp();
		}

		#region IDisposable Members

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void Dispose() {
			cleanUp();
		}

		#endregion
	}

	public class IBRxClient : EWrapper {
		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void notifySubjects<T>(T obj, params dynamic[] subjects) where T : IBResponse {
			foreach(var subject in subjects) {
				subject.OnNext(obj);
			}
		}

		protected readonly static SubjectFactory sf = SubjectFactory.Instance;

		#region EWrapper Members
		protected readonly ISubject<IBResponse> IBResponseSubject = sf.GetNew<IBResponse>();
        public IObservable<IBResponse> IBResponse { get { return IBResponseSubject; } }

		protected readonly ISubject<ServerConnectionResponse> ServerConnectionMessageSubject = sf.GetNew<ServerConnectionResponse>();
		public IObservable<ServerConnectionResponse> ServerConnectionMessage { get { return ServerConnectionMessageSubject; } }

		protected readonly ISubject<BaseIBError> IBErrorSubject = sf.GetNew<BaseIBError>();
		public IObservable<BaseIBError> IBError { get { return IBErrorSubject; } }

		protected readonly ISubject<IBExError> IBExErrorSubject = sf.GetNew<IBExError>();
		public IObservable<IBExError> IBExError { get { return IBExErrorSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void error(Exception e) {
			notifySubjects(new IBExError(e), IBExErrorSubject, IBErrorSubject, ServerConnectionMessageSubject, IBResponseSubject);
		}

		protected readonly ISubject<StrError> IBStrErrorSubject = sf.GetNew<StrError>();
		public IObservable<StrError> IBStrError { get { return IBStrErrorSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void error(string str) {
			notifySubjects(new StrError(str), IBStrErrorSubject, IBErrorSubject, ServerConnectionMessageSubject, IBResponseSubject);
		}

		protected readonly ISubject<IBStandardizedError> IBStandardizedErrorSubject = sf.GetNew<IBStandardizedError>();
		public IObservable<IBStandardizedError> IBStandardizedError { get { return IBStandardizedErrorSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void error(int id, int errorCode, string errorMsg) {
			notifySubjects(new IBStandardizedError(id, errorCode, errorMsg), IBStandardizedErrorSubject, IBErrorSubject, ServerConnectionMessageSubject, IBResponseSubject);
		}

		protected readonly ISubject<CurrentTime> CurrentTimeSubject = sf.GetNew<CurrentTime>();
		public IObservable<CurrentTime> CurrentTime { get { return CurrentTimeSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void currentTime(long time) {
			notifySubjects(new CurrentTime(time), CurrentTimeSubject, ServerConnectionMessageSubject, IBResponseSubject);
		}

		protected readonly ISubject<ConnectionClosed> ConnectionClosedSubject = sf.GetNew<ConnectionClosed>();
		public IObservable<ConnectionClosed> ConnectionClosed { get { return ConnectionClosedSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void connectionClosed() {
			notifySubjects(new ConnectionClosed(), ConnectionClosedSubject, ServerConnectionMessageSubject, IBResponseSubject);
		}

		protected readonly ISubject<IBMarketData> IBMarketDataSubject = sf.GetNew<IBMarketData>();
		public IObservable<IBMarketData> IBMarketData { get { return IBMarketDataSubject; } }

		protected readonly ISubject<TickPrice> TickPriceSubject = sf.GetNew<TickPrice>();
		public IObservable<TickPrice> TickPrice { get { return TickPriceSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
        public void tickPrice(int tickerId, int field, double price, int canAutoExecute) {
            notifySubjects(new TickPrice(tickerId, field, price, canAutoExecute), IBMarketDataSubject, TickPriceSubject, IBResponseSubject);
		}

		protected readonly ISubject<TickSize> TickSizeSubject = sf.GetNew<TickSize>();
		public IObservable<TickSize> TickSize { get { return TickSizeSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void tickSize(int tickerId, int field, int size) {
			notifySubjects(new TickSize(tickerId, field, size), TickSizeSubject, IBMarketDataSubject, IBResponseSubject);
		}

		protected readonly ISubject<TickString> TickStringSubject = sf.GetNew<TickString>();
		public IObservable<TickString> TickString { get { return TickStringSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void tickString(int tickerId, int field, string value) {
			notifySubjects(new TickString(tickerId, field, value), TickStringSubject, IBMarketDataSubject, IBResponseSubject);
		}

		protected readonly ISubject<TickGeneric> TickGenericSubject = sf.GetNew<TickGeneric>();
		public IObservable<TickGeneric> TickGeneric { get { return TickGenericSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void tickGeneric(int tickerId, int field, double value) {
			notifySubjects(new TickGeneric(tickerId, field, value), TickGenericSubject, IBMarketDataSubject, IBResponseSubject);
		}

		protected readonly ISubject<TickEFP> TickEFPSubject = sf.GetNew<TickEFP>();
		public IObservable<TickEFP> TickEFP { get { return TickEFPSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void tickEFP(int tickerId, int tickType, double basisPoints, string formattedBasisPoints, double impliedFuture, int holdDays, string futureExpiry, double dividendImpact, double dividendsToExpiry) {
			notifySubjects(new TickEFP(tickerId, tickType, basisPoints, formattedBasisPoints, impliedFuture, holdDays, futureExpiry, dividendImpact, dividendsToExpiry), TickEFPSubject, IBMarketDataSubject, IBResponseSubject);
		}

		protected readonly ISubject<TickOptionComputation> TickOptionComputationSubject = sf.GetNew<TickOptionComputation>();
		public IObservable<TickOptionComputation> TickOptionComputation { get { return TickOptionComputationSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void tickOptionComputation(int tickerId, int field, double impliedVolatility, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice) {
			notifySubjects(new TickOptionComputation(tickerId, field, impliedVolatility, delta, optPrice, pvDividend, gamma, vega, theta, undPrice), TickOptionComputationSubject, IBMarketDataSubject, IBResponseSubject);
		}

		protected readonly ISubject<TickSnapshotEnd> TickSnapshotEndSubject = sf.GetNew<TickSnapshotEnd>();
		public IObservable<TickSnapshotEnd> TickSnapshotEnd { get { return TickSnapshotEndSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void tickSnapshotEnd(int tickerId) {
			notifySubjects(new TickSnapshotEnd(tickerId), TickSnapshotEndSubject, IBMarketDataSubject, IBResponseSubject);
		}

		protected readonly ISubject<DeltaNeutralValidation> DeltaNeutralValidationSubject = sf.GetNew<DeltaNeutralValidation>();
		public IObservable<DeltaNeutralValidation> DeltaNeutralValidation { get { return DeltaNeutralValidationSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void deltaNeutralValidation(int reqId, UnderComp underComp) {
			notifySubjects(new DeltaNeutralValidation(reqId, underComp), DeltaNeutralValidationSubject, IBMarketDataSubject, IBResponseSubject);
		}

		protected readonly ISubject<MarketDataType> MarketDataTypeSubject = sf.GetNew<MarketDataType>();
		public IObservable<MarketDataType> MarketDataType { get { return MarketDataTypeSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void marketDataType(int reqId, int marketDataType) {
			notifySubjects(new MarketDataType(reqId, marketDataType), MarketDataTypeSubject, IBMarketDataSubject, IBResponseSubject);
		}

		protected readonly ISubject<OrderBase> OrderRelatedSubject = sf.GetNew<OrderBase>();
		public IObservable<OrderBase> OrderRelated { get { return OrderRelatedSubject; } }

		protected readonly ISubject<NextValidId> NextValidIdSubject = sf.GetNew<NextValidId>();
		public IObservable<NextValidId> NextValidId { get { return NextValidIdSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void nextValidId(int orderId) {
			notifySubjects(new NextValidId(orderId), NextValidIdSubject, OrderRelatedSubject, IBResponseSubject);
		}

		protected readonly ISubject<OrderStatus> OrderStatusSubject = sf.GetNew<OrderStatus>();
		public IObservable<OrderStatus> OrderStatus { get { return OrderStatusSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void orderStatus(int orderId, string status, int filled, int remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, string whyHeld) {
			notifySubjects(new OrderStatus(orderId, status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld), OrderStatusSubject, OrderRelatedSubject, IBResponseSubject);
		}

		protected readonly ISubject<OpenOrder> OpenOrderSubject = sf.GetNew<OpenOrder>();
		public IObservable<OpenOrder> OpenOrder { get { return OpenOrderSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void openOrder(int orderId, Contract contract, Order order, OrderState orderState) {
			notifySubjects(new OpenOrder(orderId, contract, order, orderState), OpenOrderSubject, OrderRelatedSubject, IBResponseSubject);
		}

		protected readonly ISubject<OpenOrderEnd> OpenOrderEndSubject = sf.GetNew<OpenOrderEnd>();
		public IObservable<OpenOrderEnd> OpenOrderEnd { get { return OpenOrderEndSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void openOrderEnd() {
			notifySubjects(new OpenOrderEnd(), OpenOrderEndSubject, OrderRelatedSubject, IBResponseSubject);
		}

		protected readonly ISubject<AccountAndPortfolio> AccountAndPortfolioSubject = sf.GetNew<AccountAndPortfolio>();
		public IObservable<AccountAndPortfolio> AccountAndPortfolio { get { return AccountAndPortfolioSubject; } }

		protected readonly ISubject<UpdateAccountValue> UpdateAccountValueSubject = sf.GetNew<UpdateAccountValue>();
		public IObservable<UpdateAccountValue> UpdateAccountValue { get { return UpdateAccountValueSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void updateAccountValue(string key, string value, string currency, string accountName) {
			notifySubjects(new UpdateAccountValue(key, value, currency, accountName), UpdateAccountValueSubject, AccountAndPortfolioSubject, IBResponseSubject);
		}

		protected readonly ISubject<UpdatePortfolio> UpdatePortfolioSubject = sf.GetNew<UpdatePortfolio>();
		public IObservable<UpdatePortfolio> UpdatePortfolio { get { return UpdatePortfolioSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void updatePortfolio(Contract contract, int position, double marketPrice, double marketValue, double averageCost, double unrealisedPNL, double realisedPNL, string accountName) {
			notifySubjects(new UpdatePortfolio(contract, position, marketPrice, marketValue, averageCost, unrealisedPNL, realisedPNL, accountName), UpdatePortfolioSubject, AccountAndPortfolioSubject, IBResponseSubject);
		}

		protected readonly ISubject<UpdateAccountTime> UpdateAccountTimeSubject = sf.GetNew<UpdateAccountTime>();
		public IObservable<UpdateAccountTime> UpdateAccountTime { get { return UpdateAccountTimeSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void updateAccountTime(string timestamp) {
			notifySubjects(new UpdateAccountTime(timestamp), UpdateAccountTimeSubject, AccountAndPortfolioSubject, IBResponseSubject);
		}

		protected readonly ISubject<PositionEvent> PositionEventSubject = sf.GetNew<PositionEvent>();
		public IObservable<PositionEvent> PositionEvent { get { return PositionEventSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void position(string account, Contract contract, int pos, double avgCost) {
			notifySubjects(new PositionEvent(account, contract, pos, avgCost), UpdateAccountTimeSubject, AccountAndPortfolioSubject, IBResponseSubject);
		}

		protected readonly ISubject<AccountDownloadEnd> AccountDownloadEndSubject = sf.GetNew<AccountDownloadEnd>();
		public IObservable<AccountDownloadEnd> AccountDownloadEnd { get { return AccountDownloadEndSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void accountDownloadEnd(string account) {
			notifySubjects(new AccountDownloadEnd(account), AccountDownloadEndSubject, AccountAndPortfolioSubject, IBResponseSubject);
		}

		protected readonly ISubject<FA> FASubject = sf.GetNew<FA>();
		public IObservable<FA> FA { get { return FASubject; } }

		protected readonly ISubject<ManagedAccounts> ManagedAccountsSubject = sf.GetNew<ManagedAccounts>();
		public IObservable<ManagedAccounts> ManagedAccounts { get { return ManagedAccountsSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void managedAccounts(string accountsList) {
			notifySubjects(new ManagedAccounts(accountsList), ManagedAccountsSubject, FASubject, IBResponseSubject);
		}

		protected readonly ISubject<ReceiveFA> ReceiveFASubject = sf.GetNew<ReceiveFA>();
		public IObservable<ReceiveFA> ReceiveFA { get { return ReceiveFASubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void receiveFA(int faDataType, string faXmlData) {
			notifySubjects(new ReceiveFA(faDataType, faXmlData), ReceiveFASubject, FASubject, IBResponseSubject);
		}

		protected readonly ISubject<AccountSummary> AccountSummarySubject = sf.GetNew<AccountSummary>();
		public IObservable<AccountSummary> AccountSummary { get { return AccountSummarySubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void accountSummary(int reqId, string account, string tag, string value, string currency) {
			notifySubjects(new AccountSummary(reqId, account, tag, value, currency), AccountSummarySubject, FASubject, IBResponseSubject);
		}

		protected readonly ISubject<AccountSummaryEnd> AccountSummaryEndSubject = sf.GetNew<AccountSummaryEnd>();
		public IObservable<AccountSummaryEnd> AccountSummaryEnd { get { return AccountSummaryEndSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void accountSummaryEnd(int reqId) {
			notifySubjects(new AccountSummaryEnd(reqId), AccountSummaryEndSubject, FASubject, IBResponseSubject);
		}

		protected readonly ISubject<Position> PositionSubject = sf.GetNew<Position>();
		public IObservable<Position> Position { get { return PositionSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void position(string account, Contract contract, int pos) {
			notifySubjects(new Position(account, contract, pos), PositionSubject, FASubject, IBResponseSubject);
		}

		protected readonly ISubject<PositionEnd> PositionEndSubject = sf.GetNew<PositionEnd>();
		public IObservable<PositionEnd> PositionEnd { get { return PositionEndSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void positionEnd() {
			notifySubjects(new PositionEnd(), PositionEndSubject, FASubject, IBResponseSubject);
		}

		protected readonly ISubject<ContractDetailsBase> ContractDetailsBaseSubject = sf.GetNew<ContractDetailsBase>();
		public IObservable<ContractDetailsBase> ContractDetailsBase { get { return ContractDetailsBaseSubject; } }

		protected readonly ISubject<ContractDetailsEvent> ContractDetailsEventSubject = sf.GetNew<ContractDetailsEvent>();
		public IObservable<ContractDetailsEvent> ContractDetailsEvent { get { return ContractDetailsEventSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void contractDetails(int reqId, ContractDetails contractDetails) {
			notifySubjects(new ContractDetailsEvent(reqId, contractDetails), ContractDetailsEventSubject, ContractDetailsBaseSubject, IBResponseSubject);
		}

		protected readonly ISubject<BondContractDetails> BondContractDetailsSubject = sf.GetNew<BondContractDetails>();
		public IObservable<BondContractDetails> BondContractDetails { get { return BondContractDetailsSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void bondContractDetails(int reqId, ContractDetails contract) {
			notifySubjects(new BondContractDetails(reqId, contract), ContractDetailsEventSubject, ContractDetailsBaseSubject, IBResponseSubject);
		}

		protected readonly ISubject<ContractDetailsEnd> ContractDetailsEndSubject = sf.GetNew<ContractDetailsEnd>();
		public IObservable<ContractDetailsEnd> ContractDetailsEnd { get { return ContractDetailsEndSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void contractDetailsEnd(int reqId) {
			notifySubjects(new ContractDetailsEnd(reqId), ContractDetailsEndSubject, ContractDetailsBaseSubject, IBResponseSubject);
		}

		protected readonly ISubject<Executions> ExecutionsSubject = sf.GetNew<Executions>();
		public IObservable<Executions> Executions { get { return ExecutionsSubject; } }

		protected readonly ISubject<ExecDetails> ExecDetailsSubject = sf.GetNew<ExecDetails>();
		public IObservable<ExecDetails> ExecDetails { get { return ExecDetailsSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void execDetails(int reqId, Contract contract, Execution execution) {
			notifySubjects(new ContractDetailsEnd(reqId), ExecDetailsSubject, ExecutionsSubject, IBResponseSubject);
		}

		protected readonly ISubject<ExecDetailsEnd> ExecDetailsEndSubject = sf.GetNew<ExecDetailsEnd>();
		public IObservable<ExecDetailsEnd> ExecDetailsEnd { get { return ExecDetailsEndSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void execDetailsEnd(int reqId) {
			notifySubjects(new ContractDetailsEnd(reqId), ExecDetailsEndSubject, ExecutionsSubject, IBResponseSubject);
		}

		protected readonly ISubject<CommissionReportEvent> CommissionReportEventSubject = sf.GetNew<CommissionReportEvent>();
		public IObservable<CommissionReportEvent> CommissionReportEvent { get { return CommissionReportEventSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void commissionReport(CommissionReport commissionReport) {
			notifySubjects(new CommissionReportEvent(commissionReport), CommissionReportEventSubject, ExecutionsSubject, IBResponseSubject);
		}

		protected readonly ISubject<FundamentalData> FundamentalDataSubject = sf.GetNew<FundamentalData>();
		public IObservable<FundamentalData> FundamentalData { get { return FundamentalDataSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void fundamentalData(int reqId, string data) {
			notifySubjects(new FundamentalData(reqId, data), FundamentalDataSubject, IBResponseSubject);
		}

		protected readonly ISubject<HistoricalDataBase> HistoricalDataBaseSubject = sf.GetNew<HistoricalDataBase>();
		public IObservable<HistoricalDataBase> HistoricalDataBase { get { return HistoricalDataBaseSubject; } }

		protected readonly ISubject<HistoricalData> HistoricalDataSubject = sf.GetNew<HistoricalData>();
		public IObservable<HistoricalData> HistoricalData { get { return HistoricalDataSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void historicalData(int reqId, string date, double open, double high, double low, double close, int volume, int count, double WAP, bool hasGaps) {
			notifySubjects(new HistoricalData(reqId, date, open, high, low, close, volume, count, WAP, hasGaps), HistoricalDataSubject, HistoricalDataBaseSubject, IBResponseSubject);
		}

		protected readonly ISubject<HistoricalDataEnd> HistoricalDataEndSubject = sf.GetNew<HistoricalDataEnd>();
		public IObservable<HistoricalDataEnd> HistoricalDataEnd { get { return HistoricalDataEndSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void historicalDataEnd(int reqId, string start, string end) {
			notifySubjects(new HistoricalDataEnd(reqId, start, end), HistoricalDataEndSubject, HistoricalDataBaseSubject, IBResponseSubject);
		}

		protected readonly ISubject<MarketDepth> MarketDepthSubject = sf.GetNew<MarketDepth>();
		public IObservable<MarketDepth> MarketDepth { get { return MarketDepthSubject; } }

		protected readonly ISubject<MarketDepthL1> MarketDepthL1Subject = sf.GetNew<MarketDepthL1>();
		public IObservable<MarketDepthL1> MarketDepthL1 { get { return MarketDepthL1Subject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void updateMktDepth(int tickerId, int position, int operation, int side, double price, int size) {
			notifySubjects(new MarketDepthL1(tickerId, position, operation, side, price, size), MarketDepthL1Subject, MarketDepthSubject, IBResponseSubject);
		}

		protected readonly ISubject<MarketDepthL2> MarketDepthL2Subject = sf.GetNew<MarketDepthL2>();
		public IObservable<MarketDepthL2> MarketDepthL2 { get { return MarketDepthL2Subject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void updateMktDepthL2(int tickerId, int position, string marketMaker, int operation, int side, double price, int size) {
			notifySubjects(new MarketDepthL2(tickerId, position, marketMaker, operation, side, price, size), MarketDepthL2Subject, MarketDepthSubject, IBResponseSubject);
		}

		protected readonly ISubject<RealTimeBars> RealTimeBarsSubject = sf.GetNew<RealTimeBars>();
		public IObservable<RealTimeBars> RealTimeBars { get { return RealTimeBarsSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void realtimeBar(int reqId, long time, double open, double high, double low, double close, long volume, double WAP, int count) {
			notifySubjects(new RealTimeBars(reqId, time, open, high, low, close, volume, WAP, count), RealTimeBarsSubject, IBResponseSubject);
		}

		protected readonly ISubject<MarketScanners> MarketScannersSubject = sf.GetNew<MarketScanners>();
		public IObservable<MarketScanners> MarketScanners { get { return MarketScannersSubject; } }

		protected readonly ISubject<ScannerParameters> ScannerParametersSubject = sf.GetNew<ScannerParameters>();
		public IObservable<ScannerParameters> ScannerParameters { get { return ScannerParametersSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void scannerParameters(string xml) {
			notifySubjects(new ScannerParameters(xml), ScannerParametersSubject, MarketScannersSubject, IBResponseSubject);
		}

		protected readonly ISubject<ScannerData> ScannerDataSubject = sf.GetNew<ScannerData>();
		public IObservable<ScannerData> ScannerData { get { return ScannerDataSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void scannerData(int reqId, int rank, ContractDetails contractDetails, string distance, string benchmark, string projection, string legsStr) {
			notifySubjects(new ScannerData(reqId, rank, contractDetails, distance, benchmark, projection, legsStr), ScannerDataSubject, MarketScannersSubject, IBResponseSubject);
		}

		protected readonly ISubject<ScannerDataEnd> ScannerDataEndSubject = sf.GetNew<ScannerDataEnd>();
		public IObservable<ScannerDataEnd> ScannerDataEnd { get { return ScannerDataEndSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void scannerDataEnd(int reqId) {
			notifySubjects(new ScannerDataEnd(reqId), ScannerDataEndSubject, MarketScannersSubject, IBResponseSubject);
		}

		protected readonly ISubject<UpdateNewsBulletin> UpdateNewsBulletinSubject = sf.GetNew<UpdateNewsBulletin>();
		public IObservable<UpdateNewsBulletin> UpdateNewsBulletin { get { return UpdateNewsBulletinSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void updateNewsBulletin(int msgId, int msgType, string message, string origExchange) {
			notifySubjects(new UpdateNewsBulletin(msgId, msgType, message, origExchange), UpdateNewsBulletinSubject, IBResponseSubject);
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void verifyMessageAPI(string apiData) {
			// TODO: Write event class, write IB API group Subject if missing and notify the relavent subjects
			throw new NotImplementedException();
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void verifyCompleted(bool isSuccessful, string errorText) {
			// TODO: Write event class, write IB API group Subject if missing and notify the relavent subjects
			throw new NotImplementedException();
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void displayGroupList(int reqId, string groups) {
			// TODO: Write event class, write IB API group Subject if missing and notify the relavent subjects
			throw new NotImplementedException();
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void displayGroupUpdated(int reqId, string contractInfo) {
			// TODO: Write event class, write IB API group Subject if missing and notify the relavent subjects
			throw new NotImplementedException();
		}
		#endregion        
	}

	public class IBRxClientRequest : EClientSocket, IObserver<IBRequests> {
		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void notifySubjects<T>(T obj, params dynamic[] subjects) where T : IBResponse {
			foreach (var subject in subjects) {
				subject.OnNext(obj);
			}
		}

		protected readonly static SubjectFactory sf = SubjectFactory.Instance;

		protected readonly ISubject<IBRequests> RequestSubject = sf.GetNew<IBRequests>();
		public IObservable<IBRequests> Requests { get { return RequestSubject; } }

		protected readonly EWrapper wrapper;

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public IBRxClientRequest(EWrapper wrapper) : base(wrapper) { 
			this.wrapper = wrapper;
			RequestSubject.Subscribe(this);
		}

		#region IObserver<IBResponse> Members

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void OnCompleted() {
			this.eDisconnect();
		}

		protected readonly ISubject<IBExError> IBExErrorSubject = sf.GetNew<IBExError>();
		public IObservable<IBExError> IBExError { get { return IBExErrorSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void OnError(Exception error) {
			this.notifySubjects(new IBExError(error), IBExErrorSubject, IBResponseSubject);
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		public void OnNext(IBRequests value) {
			this.processDynamic(value);
		}

		#endregion

		protected readonly ISubject<IBResponse> IBResponseSubject = sf.GetNew<IBResponse>();
        public IObservable<IBResponse> IBResponse { get { return IBResponseSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void processDynamic(dynamic value) {
			this.process(value);
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void process(EConnect value) {
			this.eConnect(value.Host, value.Port, value.ClientId);
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void process(EDisconnect value) {
			this.eDisconnect();
		}

		protected readonly ISubject<IsConnectedResponse> IsConnectedResponseSubject = sf.GetNew<IsConnectedResponse>();
		public IObservable<IsConnectedResponse> IsConnectedResponse { get { return IsConnectedResponseSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void process(IsConnected value) {
			this.notifySubjects(new IsConnectedResponse(this.IsConnected()), IsConnectedResponseSubject, IBResponseSubject);
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void process(SetServerLogLevel value) {
			this.setServerLogLevel((int) value.LogLevel);
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void process(ReqCurrentTime value) {
			this.reqCurrentTime();
		}

		protected readonly ISubject<ServerVersionResponse> ServerVersionResponseSubject = sf.GetNew<ServerVersionResponse>();
		public IObservable<ServerVersionResponse> ServerVersionResponse { get { return ServerVersionResponseSubject; } }

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void process(ServerVersion value) {
			this.notifySubjects(new ServerVersionResponse(this.ServerVersion), ServerVersionResponseSubject, IBResponseSubject);
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void process(TwsConnectionTime value) {
			// TODO: Fix this when API becomes available	
			throw new NotImplementedException("Connection time not implimented in .NET API yet");
		}

		[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
		protected virtual void process(ReqGlobalCancel value) {
			this.reqGlobalCancel();
		}
	}
}
